(() => {
  // ---------------------联合类型---------------------
  /**
   * 联合类型
   * 1. 你只能从允许的字符中选择其一来做为参数传递，传入其它值则会产生错误。
   * 2. 联合类型可以用 | 分隔多个类型，表示可以是多个类型中的一个。
   * 3. 字符串字面量类型允许你指定字符串必须的固定值。
   * 4. 联合类型可以用 instanceof 关键字来判断一个变量是否属于某个类型。
   * 5. 联合类型可以用 in 关键字来判断一个变量是否属于某个联合类型。
   * 6. 联合类型可以用 typeof 关键字来获取一个变量的类型。
   */
  // 1. 定义
  let myPhone: number | string = '010-820'
  // let myPhone1: number | string = true 报错

  // 2. 字符串字面量类型
  type Easing = 'ease-in' | 'ease-out' | 'ease-in-out'
  class UIElement {
    animate(dx: number, dy: number, easing: Easing) {
      if (easing === 'ease-in') {
      }
      else if (easing === 'ease-out') {
      }
      else if (easing === 'ease-in-out') {
      } else {
        // 这里会报错，因为类型断言失败
      }
    }
  }
  let button = new UIElement()
  button.animate(0, 0, 'ease-in')
  button.animate(0, 0, 'ease-out')
  button.animate(0, 0, 'ease-in-out')
  // button.animate(0,0,'other') // 报错

  // 3. 数字字面量类型
  type MyNumber = 1 | 2 | 3
  let num: MyNumber = 2
  // let num1: MyNumber = 4 报错

  // ---------------------交叉类型---------------------
  /**
   * 交叉类型
   * 1. 交叉类型是将多个类型合并为一个类型。
   * 2. 交叉类型可以用 & 分隔多个类型，表示可以同时是多个类型。
   * 3. 交叉类型如果出现了同名的属性，且类型不统一兼容，则报错
   */
  interface People {
    age: number
    name: string
    sex: string | number
  }
  interface Man {
    sex: number | string
  }
  const xiaoman = (man: Man & People) => {
    console.log(man.age);
    console.log(man.name);
    console.log(man.sex);
  }
  xiaoman({ age: 20, name: 'xiaoman', sex: 'male' }) // 20 xiaoman male

  // ---------------------类型断言---------------------
  /**
   * 类型断言
   * 1. 类型断言是一种强制类型转换，它允许你告诉编译器，你相信这个变量是某种类型。
   * 2. 类型断言有两种形式。 其一是“尖括号”语法，另一个为as语法。
   * 3. 类型断言只能够「欺骗」TypeScript 编译器，无法避免运行时的错误，滥用类型断言可能会导致运行时错误。
   */

  // 1. 尖括号语法
  /**
   * any类型
   * 1. 使用any类型会禁用TypeScript的类型检查机制
   * 2. 任何类型都可以赋值给any类型
   * 3. 过度使用any类型会失去TypeScript的类型安全优势，因此在实际开发中应尽量避免滥用any类型。
   */
  let someValue: any = "this is a string"
  let strLength: number = (<string>someValue).length
  console.log(strLength);

  // 2. as语法
  let someValue1: any = "this is a string"
  let strLength1: number = (someValue as string).length

  // ---------------------联合类型和断言---------------------
  /**
   * 联合类型和断言
   * 1. 使用联合类型调用某个接口的属性时，需要类型断言来指定接口
   */
  interface A {
    run: string
  }
  interface B {
    jump: string
  }

  const fn = (type: A | B): string => {
    return (type as A).run
  }

  // ---------------------as const---------------------
  /**
   * as const
   * 1. as const 语法可以将对象字面量转换为只读类型
   * 2. 它可以用来创建一组常量，这些常量的值不能被修改
   * 3. as const 无法修改数组（增删改），const可以，因为const不会改变指针指向
   */

  const names = '小满'
  // names = 'aa' //无法修改

  let names2 = '小满' as const
  // names2 = 'aa' //无法修改

  // 数组
  let a1 = [10, 20] as const;
  const a2 = [10, 20];

  // a1.unshift(30); // 错误，此时已经断言字面量为[10, 20],数据无法做任何修改
  a2.unshift(30); // 通过，没有修改指针
})()


